a tool for shared writing and social publishing
at feature/recommend 118 lines 3.7 kB view raw
1import { z } from "zod"; 2import { makeRoute } from "../lib"; 3import type { Env } from "./route"; 4import { AtUri } from "@atproto/syntax"; 5import { getFactsFromHomeLeaflets } from "./getFactsFromHomeLeaflets"; 6import { normalizeDocumentRecord } from "src/utils/normalizeRecords"; 7import { ids } from "lexicons/api/lexicons"; 8 9export type GetPublicationDataReturnType = Awaited< 10 ReturnType<(typeof get_publication_data)["handler"]> 11>; 12export const get_publication_data = makeRoute({ 13 route: "get_publication_data", 14 input: z.object({ 15 did: z.string(), 16 publication_name: z.string(), 17 }), 18 handler: async ( 19 { did, publication_name }, 20 { supabase }: Pick<Env, "supabase">, 21 ) => { 22 let pubLeafletUri; 23 let siteStandardUri; 24 if (/^(?!\.$|\.\.S)[A-Za-z0-9._:~-]{1,512}$/.test(publication_name)) { 25 pubLeafletUri = AtUri.make( 26 did, 27 ids.PubLeafletPublication, 28 publication_name, 29 ).toString(); 30 siteStandardUri = AtUri.make( 31 did, 32 ids.SiteStandardPublication, 33 publication_name, 34 ).toString(); 35 } 36 let { data: publication, error } = await supabase 37 .from("publications") 38 .select( 39 `*, 40 documents_in_publications(documents( 41 *, 42 comments_on_documents(count), 43 document_mentions_in_bsky(count), 44 recommends_on_documents(count) 45 )), 46 publication_subscriptions(*, identities(bsky_profiles(*))), 47 publication_domains(*), 48 leaflets_in_publications(*, 49 documents(*), 50 permission_tokens(*, 51 permission_token_rights(*), 52 custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*) 53 ) 54 )`, 55 ) 56 .or( 57 `name.eq."${publication_name}", uri.eq."${pubLeafletUri}", uri.eq."${siteStandardUri}"`, 58 ) 59 .eq("identity_did", did) 60 .order("uri", { ascending: false }) 61 .limit(1) 62 .single(); 63 64 let leaflet_data = await getFactsFromHomeLeaflets.handler( 65 { 66 tokens: 67 publication?.leaflets_in_publications.map( 68 (l) => l.permission_tokens?.root_entity!, 69 ) || [], 70 }, 71 { supabase }, 72 ); 73 74 // Pre-normalize documents from documents_in_publications 75 const documents = (publication?.documents_in_publications || []) 76 .map((dip) => { 77 if (!dip.documents) return null; 78 const normalized = normalizeDocumentRecord( 79 dip.documents.data, 80 dip.documents.uri, 81 ); 82 if (!normalized) return null; 83 return { 84 uri: dip.documents.uri, 85 record: normalized, 86 indexed_at: dip.documents.indexed_at, 87 sort_date: dip.documents.sort_date, 88 data: dip.documents.data, 89 commentsCount: dip.documents.comments_on_documents[0]?.count || 0, 90 mentionsCount: dip.documents.document_mentions_in_bsky[0]?.count || 0, 91 recommendsCount: 92 dip.documents.recommends_on_documents?.[0]?.count || 0, 93 }; 94 }) 95 .filter((d): d is NonNullable<typeof d> => d !== null); 96 97 // Pre-filter drafts (leaflets without published documents, not archived) 98 const drafts = (publication?.leaflets_in_publications || []) 99 .filter((l) => !l.documents) 100 .filter((l) => !(l as { archived?: boolean }).archived) 101 .map((l) => ({ 102 leaflet: l.leaflet, 103 title: l.title, 104 permission_tokens: l.permission_tokens, 105 // Keep the full leaflet data for LeafletList compatibility 106 _raw: l, 107 })); 108 109 return { 110 result: { 111 publication, 112 documents, 113 drafts, 114 leaflet_data: leaflet_data.result, 115 }, 116 }; 117 }, 118});